package edison.jcr;

import javax.jcr.AccessDeniedException;
import javax.jcr.InvalidItemStateException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.ItemVisitor;
import javax.jcr.Node;
import javax.jcr.ReferentialIntegrityException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.version.VersionException;
import org.apache.commons.lang.NullArgumentException;

import edison.persistence.Dialect;
import edison.utils.Configuration;

public abstract class ItemImpl implements Item {

	// protected final JcrPath path;
	protected final JcrName name;
	private final boolean isNode;
	protected final SessionContext context;
	private boolean isNew;
	private boolean isModified;
	protected final Dialect dialect;
	protected static final ValueFactory VALUE_FACTORY = new ValueFactoryImpl();

	public ItemImpl(SessionContext context, String name, boolean isNode) throws RepositoryException {
		this.name = new JcrName(name);
		this.isNode = isNode;
		this.context = context;
		dialect = Configuration.getDialect();
	}

	public String getPath() throws RepositoryException {
		return path.toString();

	}

	public String getName() throws RepositoryException {
		return name.toString();

	}

	public Item getAncestor(int depth) throws ItemNotFoundException, AccessDeniedException, RepositoryException {
		String ancestorPath = path.getAncestor(depth);
		if (ancestorPath == null)
			throw new ItemNotFoundException();

		return getItemByPath(ancestorPath);
	}

	protected abstract Item getItemByPath(String path);

	public Node getParent() throws ItemNotFoundException, AccessDeniedException, RepositoryException {
		String ancestorPath = path.getParent();
		if (ancestorPath == null)
			throw new ItemNotFoundException();

		return (Node) getItemByPath(ancestorPath);
	}

	public int getDepth() throws RepositoryException {
		return path.getDepth();
	}

	public Session getSession() throws RepositoryException {
		return context.getSession();
	}

	public boolean isNode() {
		return isNode;
	}

	public boolean isNew() {
		return isNew;
	}

	public boolean isModified() {
		return isModified;
	}

	public boolean isSame(Item otherItem) throws RepositoryException {

		if (otherItem == null)
			throw new NullArgumentException("otherItem");

		if (!isSameRepository(otherItem))
			return false;

		if (!isSameWorkspace(otherItem))
			return false;

		return true;
	}

	private boolean isSameRepository(Item otherItem) throws RepositoryException {
		String repositoryName = this.getSession().getRepository().getDescriptor(Repository.REP_NAME_DESC);
		String otherRepositoryName = otherItem.getSession().getRepository().getDescriptor(Repository.REP_NAME_DESC);
		return repositoryName.equals(otherRepositoryName);
	}

	private boolean isSameWorkspace(Item otherItem) throws RepositoryException {
		String repositoryName = this.getSession().getWorkspace().getName();
		String otherRepositoryName = otherItem.getSession().getWorkspace().getName();
		return repositoryName.equals(otherRepositoryName);
	}

	public void accept(ItemVisitor visitor) throws RepositoryException {
		// TODO Auto-generated method stub

	}

	public void save() throws AccessDeniedException, ItemExistsException, ConstraintViolationException, InvalidItemStateException, ReferentialIntegrityException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void refresh(boolean keepChanges) throws InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void remove() throws VersionException, LockException, ConstraintViolationException, AccessDeniedException, RepositoryException {
		// TODO Auto-generated method stub

	}
}